package com.rui.proxy.main;

import com.rui.proxy.model.CGLBProxyPoint;
import com.rui.proxy.model.DynamicProxyPoint;
import com.rui.proxy.model.StaticProxyPoint;
import com.rui.proxy.obj.GuangzhouTrainStation;
import com.rui.proxy.obj.ShenzhenTrainStation;
import com.rui.proxy.obj.TrainStation;

/**
 * 代理模式（Proxy Pattern）
 * <p>
 * 代理模式是指为其他对象提供一种代理，以控制对这个对象的访问。代理对象在访问对象和目标对象之间起到中介作用。
 * Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成，而动态代理代理类则是在Java运行时动态生成。
 * 动态代理又有JDK代理和CGLib代理两种。
 * <p>
 * 代理（Proxy）模式分为三种角色：
 * 抽象角色（Subject）： 通过接口或抽象类声明真实角色和代理对象实现的业务方法。
 * 真实角色（Real Subject）： 实现了抽象角色中的具体业务，是代理对象所代表的真实对象，是最终要引用的对象。
 * 代理角色（Proxy） ： 提供了与真实角色相同的接口，其内部含有对真实角色的引用，它可以访问、控制或扩展真实角色的功能。
 * <p>
 * 优点：
 * 使用简单、维护成本低。
 * Java原生支持，不需要任何依赖。
 * 解决了静态代理存在的多数问题。
 * <p>
 * 缺点：
 * 由于使用反射，性能会比较差。
 * 只支持接口实现，不支持继承， 不满足所有业务场景。
 * <p>
 * <p>
 * 两种动态代理的对比：
 * <p>
 * JDK动态代理的特点：
 * 需要实现InvocationHandler接口， 并重写invoke方法。
 * 被代理类需要实现接口， 它不支持继承。
 * JDK 动态代理类不需要事先定义好， 而是在运行期间动态生成。
 * JDK 动态代理不需要实现和被代理类一样的接口， 所以可以绑定多个被代理类。
 * 主要实现原理为反射， 它通过反射在运行期间动态生成代理类， 并且通过反射调用被代理类的实际业务方法。
 * <p>
 * cglib的特点：
 * cglib动态代理中使用的是FastClass机制。
 * cglib生成字节码的底层原理是使用ASM字节码框架。
 * cglib动态代理需创建3份字节码，所以在第一次使用时会比较耗性能，但是后续使用较JDK动态代理方式更高效，适合单例bean场景。
 * cglib由于是采用动态创建子类的方法，对于final方法，无法进行代理。
 *
 * @author ZhangRui
 * @date 2023/03/02 15:09
 **/
public class ProxyMain {


    public static void main(String[] args) {

        System.out.println("----------静态代理--------------");
        StaticProxyPoint staticProxyPoint = new StaticProxyPoint();
        // 代售加收5%手续费
        // 广州火车站卖票啦
        staticProxyPoint.sellTickets();


        System.out.println("----------动态代理--------------");
        DynamicProxyPoint proxy = new DynamicProxyPoint();

        TrainStation guangzhouTrainStation = proxy.getProxyObject(new GuangzhouTrainStation());
        // 代售火车票收取5%手续费
        // 广州火车站卖票啦
        guangzhouTrainStation.sellTickets();
        guangzhouTrainStation.refund();

        TrainStation shenzhenTrainStation = proxy.getProxyObject(new ShenzhenTrainStation());
        // 代售火车票收取5%手续费
        // 深圳火车站卖票啦
        shenzhenTrainStation.sellTickets();


        System.out.println("----------CGLB动态代理--------------");
        CGLBProxyPoint cglbProxyPoint = new CGLBProxyPoint();

        TrainStation gzTrainStation = cglbProxyPoint.getProxyObject(GuangzhouTrainStation.class);
        // 代售火车票收取5%手续费
        // 广州火车站卖票啦
        gzTrainStation.sellTickets();
        gzTrainStation.refund();

        TrainStation szTrainStation = cglbProxyPoint.getProxyObject(ShenzhenTrainStation.class);
        // 代售火车票收取5%手续费
        // 深圳火车站卖票啦
        szTrainStation.sellTickets();
    }
}
